package com.habitsoft.glassfish.dashboard.client;

import java.util.HashMap;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.habitsoft.kiyaa.metamodel.ModelCollection;
import com.habitsoft.kiyaa.util.AsyncCallbackProxy;
import com.habitsoft.kiyaa.views.BaseCollectionView;
import com.habitsoft.kiyaa.views.GeneratedHTMLView;
import com.habitsoft.kiyaa.views.TableView;
import com.habitsoft.kiyaa.views.TableView.RowStyleHandler;

public abstract class LogView implements GeneratedHTMLView {
    Dashboard controller;
    String currentLog="server.log";
    String filter;
    Labels labels = GWT.create(Labels.class);
    Messages messages = GWT.create(Messages.class);
    BaseCollectionView<String> logList;
    RowStyleHandler<String> rowStyleHandler = new RowStyleHandler<String>() {
        public String getStyle(int rowNumber, String log) {
            //GWT.log("Assigning style to row "+rowNumber+" severity "+getMessageSeverity(log), null);
            return getMessageSeverity(log);
        }
    };
    TableView<String> logMessagesTable;
    boolean lastPage=true;
    
    ModelCollection<String> logMessages = new ModelCollection<String>() {
        public Object getId() {
            return currentLog;
        }
        public void getLength(com.google.gwt.user.client.rpc.AsyncCallback<Integer> callback) {
            //Log.info("Reading length of logfile "+currentLog+" with filter "+filter);
            if(currentLog == null) callback.onSuccess(0);
            else if(lastPage) controller.getLogsNoCache().countLogMessages(currentLog, filter, callback);
            else {
                controller.getLogs().countLogMessages(currentLog, filter, callback);
            }
        }
        public void load(int offset, int limit, AsyncCallback<String[]> callback) {
            //Log.info("Reading from logfile "+currentLog+" with filter "+filter+" from "+offset+" limit "+limit);
            if(currentLog == null) callback.onSuccess(new String[0]);
            else if(lastPage)
                controller.getLogsNoCache().getLogMessages(currentLog, filter, offset, limit, callback);
            else {
                controller.getLogs().getLogMessages(currentLog, filter, offset, limit, callback);
            }
        }
    };
    
    public Dashboard getController() {
        return controller;
    }

    public void setController(Dashboard controller) {
        this.controller = controller;
    }

    static class LogState {
        int offset;
        boolean lastPage;
        public LogState(int offset, boolean lastPage) {
            this.offset = offset;
            this.lastPage = lastPage;
        }
    }
    HashMap<String,LogState> logStateMemory = new HashMap<String, LogState>();
    
    public String getCurrentLog() {
        return currentLog;
    }

    public void setCurrentLog(String currentLog) {
        if(currentLog != this.currentLog) {
            logStateMemory.put(currentLog, new LogState(logMessagesTable.getStartOffset(), lastPage));
            this.currentLog = currentLog;
            LogState mem = logStateMemory.get(currentLog);
            if(mem != null) {
                lastPage = mem.lastPage;
                logMessagesTable.setStartOffset(mem.offset);
            }
        }
    }

    public String getFilter() {
        return filter;
    }

    public void setFilter(String filter) {
        this.filter = filter;
    }

    public Labels getLabels() {
        return labels;
    }

    public Messages getMessages() {
        return messages;
    }

    public ModelCollection<String> getLogMessages() {
        return logMessages;
    }
    
    protected String getMessageTimestamp(String log) {
        String timestamp = log.replaceFirst("\\[#\\|([0-9-]+)T([0-9:.]+)(.*[\r\n]*)*", "$1\n$2");
        //GWT.log("Timestamp from "+log+" is "+timestamp, null);
        return timestamp;
    }
    protected String getMessageSeverity(String log) {
        String severity = log.replaceFirst("\\[#\\|[0-9T:.-]+\\|([A-Z_]+)\\|(.*[\r\n]*)*", "$1");
        return severity;
    }
    protected String getMessageLogger(String log) {
        String logger = log.replaceFirst("\\[#\\|[0-9T:.-]+\\|[A-Z_]+\\|(A-Za-z0-9._]+\\|([A-Z_]+)\\|(.*[\r\n]*)*", "$1");
        return logger;
    }
    protected String getMessageHtml(String log, boolean showStackTrace) {
        log = log.replace("<", "&lt;").replace("&", "&amp;").replace(">", "&gt;");
        log = log.replaceAll("[\r\n]+", "<br/>");
        String msg = log.replaceFirst("\\[#\\|[^|]+\\|[A-Z_]+\\|[^|]+\\|[^|]+\\|[^|]+\\|((.*[\r\n]*)*)", "$1");
        if(!showStackTrace)
            msg = msg.replaceAll("\tat [a-zA-Z0-9_.]+\\([^)]*\\).*", "");
        else
            msg = msg.replaceAll("([\n\r]+[ \t]+at )([^\n\r]+\\()(.*)(\\)[\r\n]+)", "<span class='stack-trace-row'>$1<span class='location'>$2<span class='file-and-line'>$3</span>$4</span></span>");
        return msg;
    }
    protected boolean hasStackTrace(String log) {
        return log.contains("\tat ");
    }

    public RowStyleHandler<String> getRowStyleHandler() {
        return rowStyleHandler;
    }

    public void setRowStyleHandler(RowStyleHandler<String> rowStyleHandler) {
        this.rowStyleHandler = rowStyleHandler;
    }

    public TableView<String> getLogMessagesTable() {
        return logMessagesTable;
    }

    public void setLogMessagesTable(TableView<String> logMessagesTable) {
        this.logMessagesTable = logMessagesTable;
    }
    
    public void load(AsyncCallback<Void> callback) {
        if(lastPage) {
            logMessages.getLength(new AsyncCallbackProxy<Integer>(callback) {
                @Override
                public void onSuccess(Integer result) {
                    logMessagesTable.setTotalItems(result);
                    logMessagesTable.gotoLastPage();
                    super.onSuccess(null);
                }
            });
        } else {
            callback.onSuccess(null);
        }
    }
    
    public boolean isLastPage() {
        return lastPage;
    }

    public void setLastPage(boolean lastPage) {
        this.lastPage = lastPage;
    }
}
